/***************************************************************************
 *   Copyright (C) 2009 by Dead_Body                                       *
 *   jamesholodnak@gmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <stdio.h>
#include <string.h>

#include "defines.h"
#include "system/config.h"
#include "pce.h"
#include "io.h"

//kludge borrowed from nesemu
static pce_t _kludge_pce;
pce_t *pce = &_kludge_pce;

//create a new pce object
void pce_init()
{
	//clear out the pce struct
	memset(pce,0,sizeof(pce_t));

	//initialize the hu6280
	hu6280_init();

	//set the hu6280 data pointer
	hu6280_setdata(&pce->cpu);
}

void pce_kill()
{
}

//try to load a rom into the nes
int pce_load(rom_t *r)
{
	int i,j;
	
	//init the pce
	pce_init();

	//set rom pointer
	pce->rom = r;

	for(i=0;i<(r->size/8192);i++) {
		pce->cpu.phys_op_page[i] = r->data + i * 8192;
		pce->cpu.phys_read_page[i] = r->data + i * 8192;
		pce->cpu.phys_write_page[i] = 0;
	}
	pce->cpu.phys_op_page[0xF7] = r->bramdata;
	pce->cpu.phys_read_page[0xF7] = r->bramdata;
	pce->cpu.phys_write_page[0xF7] = r->bramdata;
	pce->cpu.phys_op_page[0xF8] = pce->ram;
	pce->cpu.phys_read_page[0xF8] = pce->ram;
	pce->cpu.phys_write_page[0xF8] = pce->ram;
	for(i=1;i<4;i++) {
		pce->cpu.phys_op_page[0xF8 + i] = pce->sgram + i * 8192;
		pce->cpu.phys_read_page[0xF8 + i] = pce->sgram + i * 8192;
		pce->cpu.phys_write_page[0xF8 + i] = pce->sgram + i * 8192;
	}
	pce->cpu.phys_op_func[0xFF] = pce_io_read;
	pce->cpu.phys_read_func[0xFF] = pce_io_read;
	pce->cpu.phys_write_func[0xFF] = pce_io_write;
	log_message("rom loaded into pce, physical mem pages set ok\n");
	return(0);
}

void pce_unload()				//unload nes rom
{
	pce->rom = 0;
}

void pce_reset(int hard)
{
	int i;

	if(hard) {
		for(i=0;i<8;i++)
			pce->cpu.memorymap[i] = i;
		memset(pce->ram,0,0x2000);
		memset(pce->sgram,0,0x8000);
//		for(i=0;i<32;i++)
//			pal_write(i,startup_pal[i]);
	}
	hu6280_reset();
	pce_vdc_reset();
	log_message("pce reset ok\n");
}

/*int ppu_event_frame()
{
        curevent = 0;
        while((u32)ppucycles >= events[curevent].timestamp)
                events[curevent++].func();
        for(;;) {
//              char buf[128];dead6502_disassembleopcode(buf,nes->cpu.pc);log_message("$%04X:  %s\n",nes->cpu.pc,buf);
                ppucycles += dead6502_step() * 3;
                if((u32)ppucycles >= 0x80000000)
                        return(1);
                while((u32)ppucycles >= (events[curevent].timestamp - scanline20_deadcycle))
                        events[curevent++].func();
                if(ppucycles >= (89342 - scanline20_deadcycle))
                        break;
        }
        ppucycles -= 89342 - scanline20_deadcycle;
        ppuframes++;
        return(0);
}*/


#define CLOCK			(double)7159090.90909090
#define FRAMECYCLES 	(u32)(CLOCK / 60)
#define LINECYCLES 		(u32)(FRAMECYCLES / 262)

int pce_frame()
{
	u64 linecycles;
	u32 c;

//	log_message("frame begin: %d\n",pce->frames);
//	while((u32)pce->cycles >= events[curevent].timestamp)
//		events[curevent++].func();
	linecycles = pce->cycles;
	while(linecycles >= LINECYCLES) {
		pce_vdc_line();
		linecycles -= LINECYCLES;
	}
	for(;;) {
//		char str[128];
//		hu6280_disassembleopcode(str,pce->cpu.pc);
//		log_message("$%04X: ($%02X $%02X $%02X)   %s       \tA=$%02X X=$%02X Y=$%02X S=$%02X F=$%02X\n",pce->cpu.pc,hu6280_read(pce->cpu.pc),hu6280_read(pce->cpu.pc+1),hu6280_read(pce->cpu.pc+2),str,pce->cpu.a,pce->cpu.x,pce->cpu.y,pce->cpu.s,pce->cpu.f);
		if((c = hu6280_step()) >= 0x80000000)
			return(1);
		pce->cycles += c;
		linecycles += c;
		while(linecycles >= LINECYCLES) {
			pce_vdc_line();
			linecycles -= LINECYCLES;
		}
//		while((u32)pce->cycles >= events[curevent].timestamp)
//			events[curevent++].func();
		if(pce->cycles >= FRAMECYCLES)
			break;
	}
	pce->cycles -= FRAMECYCLES;
	pce->frames++;
	return(0);
}

void pce_burn(u32 cycles)
{
	hu6280_burn(cycles);
}

